﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace GameStateManagement
{
    public class Wormhole : OrbitingActor
    {
        private static float WormholeGravityConstant = 40f;
        private static int WormholeCooldown = 1000; // How many ticks to wait before making a wormhole active to a recent teleportee

        Utils.Timer m_WormholeKillTimer = new Utils.Timer();
        Wormhole m_Partner;
        int m_Lifetime;

        float m_fMagnitudeRatio;

        private Dictionary<WormholeObject, Force> objForces = new Dictionary<WormholeObject, Force>();

        public Wormhole(Game game, int lifetime, float magnitudeRatio, float speed)
            : base(game)
        {
            sMeshName = "BlackHole";

            // Physics
            fMass = 1000000.0f;
            fTerminalVelocity = 0f;
            vAcceleration = Vector3.Zero;
            bPhysicsDriven = true;

            m_Partner = null;
            this.m_Lifetime = lifetime;

            m_fMagnitudeRatio = magnitudeRatio;
            m_fSpeed = speed;
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            if (m_Lifetime > 0)
                m_WormholeKillTimer.AddTimer("WormholeDestroyer", m_Lifetime, new Utils.TimerDelegate(TimerKillWormhole), false);

            base.Initialize();
        }

        public override void Update(GameTime gameTime)
        {
            if (!GameplayScreen.pause && !GameplayScreen.gameOver)
            {
                m_WormholeKillTimer.Update(gameTime); // Tick the timer

                // Scale the radius to the shrinking sphere.
                ScaleRadiusBetweenSphereAndPlanet(m_fMagnitudeRatio);

                foreach (WormholeObject wormholeTarget in WormholeManager.wormholeObjs)
                {
                    // Get the force object from the dictionary, or create it and store it if it doesn't exist.
                    Force force;
                    if (!objForces.TryGetValue(wormholeTarget, out force))
                    {
                        force = wormholeTarget.m_Obj.CreateForce("Wormhole");
                        objForces.Add(wormholeTarget, force);
                    }

                    force.vec = Vector3.Zero;

                    if (System.Environment.TickCount - wormholeTarget.lastTeleport > Wormhole.WormholeCooldown)
                    {
                        // Distance between looping object and this wormhole.
                        Vector3 vecBetween = this.m_vWorldPosition - wormholeTarget.m_Obj.m_vWorldPosition;
                        float dist = vecBetween.Length();

                        if (wormholeTarget.m_fMinDist <= 0 || dist < wormholeTarget.m_fMinDist)
                        {
                            if (dist > WorldBounds.Radius + wormholeTarget.m_Obj.WorldBounds.Radius)
                            {
                                vecBetween.Normalize();
                                float gravity = (Wormhole.WormholeGravityConstant * (this.fMass * wormholeTarget.m_Obj.fMass) / (float)Math.Pow(dist, 2.0)) * wormholeTarget.m_fMultiplier;
                                force.vec = gravity * vecBetween;
                            }
                        }
                    }
                }

                base.Update(gameTime);
            }
        }

        public Wormhole GetPartner()
        {
            return m_Partner;
        }

        public void SetPartner(Wormhole partner)
        {
            m_Partner = partner;
        }

        public void ObjCollide(WormholeObject wormholeObj)
        {
            if (System.Environment.TickCount - wormholeObj.lastTeleport > Wormhole.WormholeCooldown)
            {
                wormholeObj.lastTeleport = System.Environment.TickCount;
                wormholeObj.m_Obj.m_vWorldPosition = m_Partner.GetWorldPosition();
            }
        }

        /// <summary>
        /// Removes this wormhole from the world.
        /// </summary>
        public void Kill()
        {
            // Clean up the forces applied by this wormhole.
            foreach (KeyValuePair<WormholeObject, Force> wormholeObj in objForces)
            {
                wormholeObj.Key.m_Obj.DeleteForce(wormholeObj.Value);
            }

            WormholeManager.GetWormholeManager().RemoveWormhole(this);
        }

        public void TimerKillWormhole()
        {
            Kill();
        }
    }
}
